package com.zdy.im.tio;

import com.sixeco.framework.util.json.JsonUtils;
import com.zdy.im.chat.ChatMessageBody;
import com.zdy.im.chat.ChatMessageInfo;
import com.zdy.im.tio.command.CmdHandler;
import com.zdy.im.tio.command.CommandHandlerManager;
import com.zdy.im.tio.command.Command;
import com.zdy.im.tio.command.ProtocolManager;
import com.zdy.im.user.dto.request.ImChatMessageRequestDto;
import com.zdy.im.user.service.ImChatMessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.stereotype.Component;
import org.tio.core.ChannelContext;
import org.tio.core.Tio;
import org.tio.core.intf.Packet;
import org.tio.http.common.HttpRequest;
import org.tio.http.common.HttpResponse;
import org.tio.http.common.HttpResponseStatus;
import org.tio.websocket.common.WsRequest;
import org.tio.websocket.common.WsResponse;
import org.tio.websocket.server.handler.IWsMsgHandler;

import javax.annotation.Resource;
import java.io.IOException;

/**
 * websocket 处理函数
 *
 * @Author 作者 : zdy
 * @CreateDate 创建时间: 2021-02-30
 */
@Component
public class TioWsRouterHandler implements IWsMsgHandler {

    private static Logger logger = LoggerFactory.getLogger(TioWsRouterHandler.class);





    @Autowired
    private ImChatMessageService imChatMessageService;

    @Resource
    @Qualifier(value = "commandManager")
    private CommandHandlerManager commandHandlerManager;


    /**
     * 握手时走这个方法，业务可以在这里获取cookie，request参数等
     * 握手时走这个方法，业务可以在这里获取cookie，request参数等
     * 功能协议路由实现拦截器;
     * @param httpRequest        request
     * @param httpResponse   httpResponse
     * @param channelContext channelContext
     * @return HttpResponse
     */
    @Override
    public HttpResponse handshake(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) {
        logger.info("handshake 握手时走这个方法，业务可以在这里获取cookie，request参数等 ");
//
        try {
            //不做业务处理，业务交逻辑交给对应的业务handler处理实现
            String cmd  = httpRequest.getParam("cmd");
            CmdHandler cmdHandler =  commandHandlerManager.getCommand(cmd);
            if(cmdHandler == null){
                logger.error("握手失败 CmdHandler is null by cmd[{}] ",cmd);
                httpResponse.setStatus(HttpResponseStatus.getHttpStatus(404));
                return httpResponse;
            }
            cmdHandler.handler(httpRequest,channelContext);
        } catch (AuthenticationException | InvalidTokenException e) {
            e.printStackTrace();
            httpResponse.setStatus(HttpResponseStatus.getHttpStatus(404));
        }catch (Exception e){
            e.printStackTrace();
        }
        return httpResponse;
    }

    /** 握手成功，绑定到群组，后面会有群发
     * @param httpRequest    httpRequest
     * @param httpResponse   httpResponse
     * @param channelContext channelContext
     * @throws Exception Exception
     * @author tanyaowu tanyaowu
     */
    @Override
    public void onAfterHandshaked(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) throws Exception {
             logger.info("握手成功协议， onAfterHandshaked ");
        try {

            CmdHandler cmdHandler = commandHandlerManager.getCommand(Command.COMMAND_LOGIN_REQ);
            if(cmdHandler == null){
                logger.error("握手失败 CmdHandler is null by cmd[{}] ",5);
                httpResponse.setStatus(HttpResponseStatus.getHttpStatus(404));
                return;
            }
            cmdHandler.handler(httpRequest,channelContext);
        }catch (Exception e){
            logger.error("握手成功协议， onAfterHandshaked Exception:",e);
        }


    }

    /**
     * 字节消息（binaryType = arraybuffer）过来后会走这个方法
     */
    @Override
    public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {
        logger.info("onBytes 接收到bytes消息 ,字节消息（binaryType = arraybuffer）过来后会走这个方法");
        return null;
    }

    /**
     * 当客户端发close flag时，会走这个方法
     */
    @Override
    public Object onClose(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {
        Tio.remove(channelContext, "receive close flag");
        return null;
    }

    /**
     * 字符消息（binaryType = blob）过来后会走这个方法
     *
     * @param wsRequest      wsRequest
     * @param text           text
     * @param channelContext channelContext
     * @return obj
     */
    @Override
    public Object onText(WsRequest wsRequest, String text, ChannelContext channelContext) {
        try {
            logger.info("onText 接收到文本消息 ,字符消息（binaryType = text）过来后会走这个方法");
            logger.info("from IWsMsgHandler reception message onText content:[{}]",text);
            ChatMessageInfo sendInfo =  JsonUtils.parseObject(text,ChatMessageInfo.class);
            if(sendInfo == null){
                String exceptionText = "发送失败";
                WsResponse wsResponse = WsResponse.fromText(exceptionText, TioServerConfig.CHARSET);
                Tio.send(channelContext, wsResponse);
                return  ProtocolManager.ResponsePacket.dataToExceptionFailed(channelContext);
            }
            CmdHandler cmdHandler =  commandHandlerManager.getCommand(sendInfo.getCmd());
            if(cmdHandler == null){
                logger.error("onText to  CmdHandler is null by cmd[{}] ",sendInfo.getCmd());
                WsResponse wsResponse = WsResponse.fromText("发送失败", TioServerConfig.CHARSET);
                return wsResponse;
            }
            Packet result = cmdHandler.handler(wsRequest,channelContext);
            return result;
        } catch (Exception e) {
            e.printStackTrace();

        }
        //返回值是要发送给客户端的内容，一般都是返回null
        return  ProtocolManager.ResponsePacket.dataToExceptionFailed(channelContext);
    }

    /**
     * 未读消息
     *
     * @param channelContext channelContext
     * @param objectMapper   objectMapper
     * @throws IOException 抛出异常
     */
//    private void sendOffLineMessage(ChannelContext channelContext, ObjectMapper objectMapper) throws IOException {
//        List<ImMessage> imMessageList = iImMessageService.getUnReadMessage(channelContext.userid);
//        for (ImMessage imMessage : imMessageList) {
//            ChatMessage message = new ChatMessage();
//            message.setId(imMessage.getToId());
//            message.setMine(false);
//            message.setType(imMessage.getType());
//            ImUser imUser = imUserService.getById(imMessage.getFromId());
//            message.setUsername(imUser.getName());
//            message.setCid(String.valueOf(imMessage.getId()));
//            message.setContent(imMessage.getContent());
//            message.setTimestamp(System.currentTimeMillis());
//            message.setFromid(imMessage.getFromId());
//            message.setAvatar(imUser.getAvatar());
//            SendMessageInfo sendInfo1 = new SendMessageInfo();
//            sendInfo1.setCode(ChatUtils.MSG_MESSAGE);
//            sendInfo1.setMessage(message);
//            WsResponse wsResponse = WsResponse.fromText(objectMapper.writeValueAsString(sendInfo1), TioServerConfig.CHARSET);
//            Tio.sendToUser(channelContext.tioConfig, message.getId(), wsResponse);
//        }
//    }

    /**
     * 保存信息
     *
     * @param message    信息
     * @param readStatus 是否已读
     */
    private void saveMessage(ChatMessageBody message, String readStatus) {
        ImChatMessageRequestDto imMessage = ImChatMessageRequestDto.build().clone(message);
        imMessage.setReadStatus(Integer.parseInt(readStatus));
//        imMessage.setToId(message.getId());
//        imMessage.setFromId(message.getFromid());
//        imMessage.setSendTime(System.currentTimeMillis());
//        imMessage.setContent(message.getContent());
//        imMessage.setReadStatus(readStatus);
//        imMessage.setType(message.getType());
        imChatMessageService.saveImChatMessage(imMessage);
    }

}
